﻿using System;
using System.Collections.Generic;
using System.IO;

using Acl.Data.Mappings;
using Acl.Dynamic;

namespace Acl.Excel;

/// <summary>
/// Excel 查询生成器
/// </summary>
public sealed class ExcelQueryBuilder
{
    private readonly ExcelQueryOptions _options;
    private readonly Workbook _workbook;

    /// <summary>
    ///
    /// </summary>
    /// <param name="excelFile"></param>
    /// <param name="sheetName"></param>
    /// <exception cref="FileNotFoundException"></exception>
    public ExcelQueryBuilder(string excelFile, string sheetName = default)
    {
        Guard.NotNullOrEmpty(excelFile, nameof(excelFile));
        if (!File.Exists(excelFile))
            throw new FileNotFoundException(excelFile);

        _workbook = new Workbook(excelFile);

        _options = new ExcelQueryOptions
        {
            ExcelFile = excelFile,
            SheetName = sheetName,
        };
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="rowSize"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public ExcelQueryBuilder RowSize(uint rowSize)
    {
        if (rowSize == 0)
            throw new ArgumentOutOfRangeException(nameof(rowSize));
        _options.RowSize = rowSize;
        return this;
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="columnSize"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public ExcelQueryBuilder ColumnSize(uint columnSize)
    {
        if (columnSize == 0)
            throw new ArgumentOutOfRangeException(nameof(columnSize));
        _options.ColumnSize = columnSize;
        return this;
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="startRowNumber"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public ExcelQueryBuilder StartRowNumber(uint startRowNumber)
    {
        if (startRowNumber == 0)
            throw new ArgumentOutOfRangeException(nameof(startRowNumber));
        _options.StartRowNumber = startRowNumber;
        return this;
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="startColumnNumber"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public ExcelQueryBuilder StartColumnNumber(uint startColumnNumber)
    {
        if (startColumnNumber == 0)
            throw new ArgumentOutOfRangeException(nameof(startColumnNumber));
        _options.StartColumnNumber = startColumnNumber;
        return this;
    }

    /// <summary>
    ///
    /// </summary>
    /// <param name="hasHeader"></param>
    /// <returns></returns>
    public ExcelQueryBuilder HasHeader(bool hasHeader)
    {
        _options.HasHeader = hasHeader;
        return this;
    }

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="handler"></param>
    /// <returns></returns>
    public ExcelQueryBuilder ColumnNameMapping<T>(Action<IColumnNameMappingBuilder<T>> handler)
    {
        _options.MappingBuilder = ColumnMappingBuilder.ColumnNameMapping(handler);
        return this;
    }

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="handler"></param>
    /// <returns></returns>
    public ExcelQueryBuilder ColumnIndexMapping<T>(Action<IColumnIndexMappingBuilder<T>> handler)
    {
        _options.MappingBuilder = ColumnMappingBuilder.ColumnIndexMapping(handler);
        return this;
    }

    /// <summary>
    /// 查询工作薄中内容，返回动态实体集合
    /// </summary>
    /// <returns></returns>
    public DynamicEntitySet Query() => _workbook.Read(_options);

    /// <summary>
    /// 加载工作薄中内容到动态实体集合中
    /// </summary>
    /// <param name="entitySet">实体集合</param>
    public void Fill(DynamicEntitySet entitySet) => _workbook.Fill(entitySet, _options);

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TModel"></typeparam>
    /// <returns></returns>
    public IEnumerable<TModel> Query<TModel>() where TModel : new() => _workbook.Read<TModel>(_options);

    /// <summary>
    ///
    /// </summary>
    /// <typeparam name="TModel"></typeparam>
    /// <param name="entities"></param>
    public void Fill<TModel>(IList<TModel> entities) where TModel : new() => _workbook.Fill(entities, _options);
}